﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
/// <summary>
/// Inclusion of PEAK PCAN-Basic namespace
/// </summary>
using Peak.Can.Basic;
using TPCANHandle = System.UInt16;
using TPCANBitrateFD = System.String;
using TPCANTimestampFD = System.UInt64;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.IO.Ports;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;
using System.Linq;
using System.Timers;
namespace ICDIBasic
{
    public partial class Form1 : Form
    {
        #region Structures
        /// <summary>
        /// Message Status structure used to show CAN Messages
        /// in a ListView
        /// </summary>
        private class MessageStatus
        {
            private TPCANMsgFD m_Msg;
            private TPCANTimestampFD m_TimeStamp;
            private TPCANTimestampFD m_oldTimeStamp;
            private int m_iIndex;
            private int m_Count;
            private bool m_bShowPeriod;
            private bool m_bWasChanged;

            public MessageStatus(TPCANMsgFD canMsg, TPCANTimestampFD canTimestamp, int listIndex)
            {
                m_Msg = canMsg;
                m_TimeStamp = canTimestamp;
                m_oldTimeStamp = canTimestamp;
                m_iIndex = listIndex;
                m_Count = 1;
                m_bShowPeriod = true;
                m_bWasChanged = false;
            }

            public void Update(TPCANMsgFD canMsg, TPCANTimestampFD canTimestamp)
            {
                m_Msg = canMsg;
                m_oldTimeStamp = m_TimeStamp;
                m_TimeStamp = canTimestamp;
                m_bWasChanged = true;
                m_Count += 1;
            }

            public TPCANMsgFD CANMsg
            {
                get { return m_Msg; }
            }

            public TPCANTimestampFD Timestamp
            {
                get { return m_TimeStamp; }
            }

            public int Position
            {
                get { return m_iIndex; }
            }

            public string TypeString
            {
                get { return GetMsgTypeString(); }
            }

            public string IdString
            {
                get { return GetIdString(); }
            }

            public string DataString
            {
                get { return GetDataString(); }
            }

            public int Count
            {
                get { return m_Count; }
            }

            public bool ShowingPeriod
            {
                get { return m_bShowPeriod; }
                set
                {
                    if (m_bShowPeriod ^ value)
                    {
                        m_bShowPeriod = value;
                        m_bWasChanged = true;
                    }
                }
            }

            public bool MarkedAsUpdated
            {
                get { return m_bWasChanged; }
                set { m_bWasChanged = value; }
            }

            public string TimeString
            {
                get { return GetTimeString(); }
            }

            private string GetTimeString()
            {
                double fTime;

                fTime = (m_TimeStamp / 1000.0);
                if (m_bShowPeriod)
                    fTime -= (m_oldTimeStamp / 1000.0);
                return fTime.ToString("F1");
            }

            private string GetDataString()
            {
                string strTemp;

                strTemp = "";

                if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_RTR) == TPCANMessageType.PCAN_MESSAGE_RTR)
                    return "Remote Request";
                else
                    for (int i = 0; i < Form1.GetLengthFromDLC(m_Msg.DLC, (m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_FD) == 0); i++)
                        strTemp += string.Format("{0:X2} ", m_Msg.DATA[i]);

                return strTemp;
            }

            private string GetIdString()
            {
                // We format the ID of the message and show it
                //
                if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_EXTENDED) == TPCANMessageType.PCAN_MESSAGE_EXTENDED)
                    return string.Format("{0:X8}h", m_Msg.ID);
                else
                    return string.Format("{0:X3}h", m_Msg.ID);
            }

            private string GetMsgTypeString()
            {
                string strTemp;
                bool isEcho = (m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_ECHO) == TPCANMessageType.PCAN_MESSAGE_ECHO;

                if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_STATUS) == TPCANMessageType.PCAN_MESSAGE_STATUS)
                    return "STATUS";

                if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_ERRFRAME) == TPCANMessageType.PCAN_MESSAGE_ERRFRAME)
                    return "ERROR";

                if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_EXTENDED) == TPCANMessageType.PCAN_MESSAGE_EXTENDED)
                    strTemp = "EXT";
                else
                    strTemp = "STD";

                if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_RTR) == TPCANMessageType.PCAN_MESSAGE_RTR)
                    strTemp += isEcho ? "/RTR [ ECHO ]" : "/RTR";
                else
                {
                    if ((int)m_Msg.MSGTYPE > (int)TPCANMessageType.PCAN_MESSAGE_EXTENDED)
                    {
                        if(isEcho)
                            strTemp += " [ ECHO";
                        else
                            strTemp += " [ ";
                        if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_FD) == TPCANMessageType.PCAN_MESSAGE_FD)
                            strTemp += " FD";
                        if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_BRS) == TPCANMessageType.PCAN_MESSAGE_BRS)
                            strTemp += " BRS";
                        if ((m_Msg.MSGTYPE & TPCANMessageType.PCAN_MESSAGE_ESI) == TPCANMessageType.PCAN_MESSAGE_ESI)
                            strTemp += " ESI";
                        strTemp += " ]";
                    }
                }

                return strTemp;
            }

        }
        #endregion

        #region Delegates
        /// <summary>
        /// Read-Delegate Handler
        /// </summary>
        private delegate void ReadDelegateHandler();
        #endregion

        #region Members
        /// <summary>
        /// Saves the desired connection mode
        /// </summary>
        /// <summary>
        /// Saves the handle of a PCAN hardware
        /// </summary>
        private byte m_Can_Send_MsgId;
        private TPCANHandle m_PcanHandle;
        /// <summary>
        /// Saves the baudrate register for a conenction
        /// </summary>
        private TPCANBaudrate m_Baudrate;
        /// <summary>
        /// Saves the type of a non-plug-and-play hardware
        /// </summary>
        private TPCANType m_HwType;
        /// <summary>
        /// Stores the status of received messages for its display
        /// </summary>
        /// <summary>
        /// Read Delegate for calling the function "ReadMessages"
        /// </summary>
        private ReadDelegateHandler m_ReadDelegate;
        /// <summary>
        /// Receive-Event
        /// </summary>
        private System.Threading.AutoResetEvent m_ReceiveEvent;
        /// <summary>
        /// Thread for message reading (using events)
        /// </summary>
        /// <summary>
        /// Handles of non plug and play PCAN-Hardware
        /// </summary>
        private TPCANHandle[] m_NonPnPHandles;
        #endregion

        #region Methods
        #region Help functions
        /// <summary>
        /// Convert a CAN DLC value into the actual data length of the CAN/CAN-FD frame.
        /// </summary>
        /// <param name="dlc">A value between 0 and 15 (CAN and FD DLC range)</param>
        /// <param name="isSTD">A value indicating if the msg is a standard CAN (FD Flag not checked)</param>
        /// <returns>The length represented by the DLC</returns>
        public static int GetLengthFromDLC(int dlc, bool isSTD)
        {
            if (dlc <= 8)
                return dlc;

             if (isSTD)
                return 8;

             switch (dlc)
             {
                case 9: return 12;
                case 10: return 16;
                case 11: return 20;
                case 12: return 24;
                case 13: return 32;
                case 14: return 48;
                case 15: return 64;
                default: return dlc;
            }
        }
        
        SerialPort sp = new SerialPort();
        string text = "";
        int g_modbus_mode = 0;  // 0 打印模式  1 指令模式
        int g_history_log_totalnum = 0;
        int g_history_log_cur_recv_num = 0;
        byte[] last_recv_data = new byte[32];
        int last_recv_data_index = 0;

        private void InitializeTty()
        {
            cbbPort.Items.AddRange(SerialPort.GetPortNames());
            sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
            cbbBaud.Text = "115200";
        }
        private bool Check_ReadInfo(Byte[] read_info_1)
        {
            byte[] readinfo;

            if (last_recv_data_index != 0)
            {
                readinfo = new byte[read_info_1.Length + last_recv_data_index];
                for (int i = 0; i < last_recv_data_index; i++)
                {
                    readinfo[i] = last_recv_data[i];
                }
                for (int i = 0; i < read_info_1.Length; i++)
                {
                    readinfo[i + last_recv_data_index] = read_info_1[i];
                }
            }
            else
            {
                readinfo = new byte[read_info_1.Length];
                for (int i = 0; i < read_info_1.Length; i++)
                {
                    readinfo[i] = read_info_1[i];
                }
            }
            for (int i = 0; i < readinfo.Length;)
            {
                if (readinfo.Length - i - 1 < 4)
                {
                    Console.WriteLine("length err:{0:D}", readinfo.Length - i - 1);
                    Array.Clear(last_recv_data, 0, last_recv_data.Length);
                    last_recv_data_index = readinfo.Length - i;
                    Array.Copy(readinfo, i, last_recv_data, 0, last_recv_data_index);
                    return false;
                }

                if ((readinfo[i] == 0x1) && (readinfo[i+1] == 0x1))
                {
                    int len = 0;
                    if (readinfo[i + 3] == 0x2)
                    {
                        len = 8;
                    }
                    else if (readinfo[i + 3] == 0x4)
                    {
                        len = 10;
                    }
                    else if (readinfo[i + 3] == 0x7) 
                    {
                        len = 6;
                    }
                    else if (readinfo[i + 3] == 0x8)
                    {
                        len = 12;
                    }
                    else if (readinfo[i + 3] == 0xc)
                    {
                        len = 10;
                    }
                    else if (readinfo[i + 3] == 0x10)
                    {
                        if (readinfo[i + 4] == 1)
                        {
                            len = 7;
                        } 
                        else if (readinfo[i + 4] == 2)
                        {
                            len = 6;
                        }
                        else if (readinfo[i + 4] == 3)
                        {
                            len = 6;
                        }
                        else if (readinfo[i + 4] == 4)
                        {
                            len = 6;
                        }
                        else if (readinfo[i + 4] == 5)
                        {
                            len = 6;
                        }
                        else if (readinfo[i + 4] == 6)
                        {
                            len = 9;
                        }
                        else if (readinfo[i + 4] == 7)
                        {
                            len = 11;
                        }
                        else if (readinfo[i + 4] == 8)
                        {
                            len = 9;
                        }
                        else if (readinfo[i + 4] == 9)
                        {
                            len = 7;
                        }
                        else if (readinfo[i + 4] == 10)
                        {
                            len = 6;
                        }
                    }

                    if (len == 0)
                    {
                        i++;
                        continue;
                    }

                    if (i + len + 1 >= readinfo.Length)
                    {
                        Console.WriteLine("length err:{0:D}", i + len);
                        Array.Clear(last_recv_data, 0, last_recv_data.Length);
                        last_recv_data_index = readinfo.Length - i;
                        Array.Copy(readinfo, i, last_recv_data, 0, last_recv_data_index);
                        return false;
                    }

                    CRC16.CRC_16 crcfunc = new CRC16.CRC_16();
                    Byte[] crc_2 = crcfunc.getcrc(readinfo, i, i + len);
                    if ((crc_2[1] == readinfo[i + len]) && (crc_2[0] == readinfo[i+len+1]))
                    {
                        byte[] new_data = new byte[len + 2];
                        Array.Copy(readinfo, i, new_data, 0, len + 2);
                        Update_ModbusInfo(new_data);
                        i += (len + 2);
                        if (i == readinfo.Length)
                        {
                            Array.Clear(last_recv_data, 0, last_recv_data.Length);
                            last_recv_data_index = 0;
                            return true;
                        }
                    } 
                    else
                    {
                        i++;
                        continue;
                    }
                }
                else if ((readinfo[i] == 0x1) && (readinfo[i + 1] == 0x5))
                {
                    int len = 0;
                    if (readinfo[i + 3] == 0xa)
                    {
                        len = 4;
                    }
                    else if (readinfo[i + 3] == 0xb)
                    {
                        len = 6;
                    }
                    if (len == 0)
                    {
                        i++;
                        continue;
                    }

                    if (i + len + 1 >= readinfo.Length)
                    {
                        Array.Clear(last_recv_data, 0, last_recv_data.Length);
                        last_recv_data_index = readinfo.Length - i;
                        Array.Copy(readinfo, i, last_recv_data, 0, last_recv_data_index);
                        return false;
                    }

                    CRC16.CRC_16 crcfunc = new CRC16.CRC_16();
                    Byte[] crc_2 = crcfunc.getcrc(readinfo, i, i + len);
                    if ((crc_2[1] == readinfo[i + len]) && (crc_2[0] == readinfo[i + len + 1]))
                    {
                        byte[] new_data = new byte[len + 2];
                        Array.Copy(readinfo, i, new_data, 0, len + 2);
                        Update_ModbusInfo(new_data);
                        i += (len + 2);
                        if (i == readinfo.Length)
                        {
                            Array.Clear(last_recv_data, 0, last_recv_data.Length);
                            last_recv_data_index = 0;
                            return true;
                        }
                    }
                    else
                    {
                        i++;
                        continue;
                    }
                }
                else
                {
                    i++;
                }

                
            }
           
            return false;
        }

        private string Get_Event_DesInfo(int event_id)
        {
            switch (event_id)
            {
                case 259:
                    return "手动上行";
                case 260:
                    return "手动下行";
                case 256:
                    return "  上位  ";
                case 257:
                    return "  中位  ";
                case 258:
                    return "  下位  ";
                case 29:
                    return "  停止  ";
                case 82:
                    return "主电故障";
                case 83:
                    return "备电故障";
                case 86:
                    return "部件故障";
                case 87:
                    return "线路故障";
                case 100:
                    return "故障恢复";
                case 21:
                    return "手动启动";
                case 20:
                    return "自动启动";
                case 45:
                    return "卷帘半降";
                case 46:
                    return "卷帘全降";
                case 23:
                    return "联动启动";
                case 81:
                    return "通信故障";
                case 57:
                    return "取消半降";
                case 58:
                    return "取消全降";
                case 59:
                    return "系统启动";
                case 60:
                    return "系统自检";
                default:
                    return "未知事件";
            }
        }

        static List<byte[]> g_history_data = new List<byte[]>();
        static int g_history_log_index = 0;

        private void analysis(int index, byte[] readinfo)
        {
            int event_id = readinfo[4] * 256 + readinfo[5];
            int year, month, day, hour, min, sec;
            year = readinfo[6] + 2000;
            month = readinfo[7];
            day = readinfo[8];
            hour = readinfo[9];
            min = readinfo[10];
            sec = readinfo[11];
            string addText = index.ToString("0000") + "  事件: " + Get_Event_DesInfo(event_id) + "  " + year.ToString("0000") + "-" + month.ToString("00") + "-" + day.ToString("00") + " " + hour.ToString("00") + ":" + min.ToString("00") + ":" + sec.ToString("00");
            checkedListBox_history.Items.Add(addText);
        }

        private void show_log_page()
        {
            int pagepernum = Convert.ToInt32(cbBox_pagepernum.Items[cbBox_pagepernum.SelectedIndex].ToString());
            if (g_history_log_totalnum - g_history_log_index < pagepernum)
            {
                pagepernum = g_history_log_totalnum - g_history_log_index;
            }
            for (int i = 0; i < pagepernum; i++)
            {
                analysis(g_history_log_index + i + 1, g_history_data[g_history_log_index + i]);
            }
        }

        private void show_homepage()
        {
            textBox_curpage.Text = "1";
            g_history_log_index = 0;
            checkedListBox_history.Items.Clear();
            show_log_page();
            return;

        }

        private void refresh_log_page()
        {
            checkedListBox_history.Items.Clear();
            show_log_page();
        }

        private void Write_2_dev()
        {
            /* 循环发送日志回写 */
            byte[] sendhex_1 = { 0x01, 0x10, 0x0, 0x9, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
            for (int i = 0; i < g_history_data.Count; i++)
            {
                sendhex_1[5] = g_history_data[g_history_data.Count - i - 1][4];
                sendhex_1[6] = g_history_data[g_history_data.Count - i - 1][5];
                sendhex_1[7] = g_history_data[g_history_data.Count - i - 1][6];
                sendhex_1[8] = g_history_data[g_history_data.Count - i - 1][7];
                sendhex_1[9] = g_history_data[g_history_data.Count - i - 1][8];
                sendhex_1[10] = g_history_data[g_history_data.Count - i - 1][9];
                sendhex_1[11] = g_history_data[g_history_data.Count - i - 1][10];
                sendhex_1[12] = g_history_data[g_history_data.Count - i - 1][11];
                send_modbus_data(sendhex_1);
                Thread.Sleep(50);
                progressBar.Value = (i + 1) * 90 / g_history_data.Count + 5;
            }

            /* 查询日志判断是否对得上 */
            Thread.Sleep(100);
            byte[] sendhex_2 = { 0x01, 0x05, 0x0, 0xb, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex_2);
        }

        private void Update_ModbusInfo(byte[] readinfo)
        {
            Console.WriteLine("Update_ModbusInfo, cmd:{0:D}, para:{1:D}", readinfo[3], readinfo[4]);
            if (readinfo[3] == 0x2)
            {
                int passwd = readinfo[4] * 256 + readinfo[5];
                textpasswd.Text = passwd.ToString("0000");
                passwd = readinfo[6] * 256 + readinfo[7];
                textRootPasswd.Text = passwd.ToString("0000");
            }
            if (readinfo[3] == 0x4)
            {
                int year, month, day, hour,min,sec;
                year = readinfo[4] + 2000;
                month = readinfo[5];
                day = readinfo[6];
                hour = readinfo[7];
                min = readinfo[8];
                sec = readinfo[9];
                text_devtime.Text = year.ToString("0000") + "-" + month.ToString("00") + "-" + day.ToString("00") + " " + hour.ToString("00") + ":" + min.ToString("00") + ":" + sec.ToString("00");
            }

            if (readinfo[3] == 7)
            {
                g_history_log_totalnum = readinfo[4] * 256 + readinfo[5];
                if (g_history_log_totalnum == 0)
                {
                    progressBar.Value = 100;
                    btn_sync_historylog.Enabled = true;
                    btn_downlog.Enabled = true;
                    progressBar.Visible = false;
                }
                lb_total_lognum.Text = g_history_log_totalnum.ToString("0000");
                int page_per_num  = Convert.ToInt32(cbBox_pagepernum.Items[cbBox_pagepernum.SelectedIndex].ToString());
                if (g_history_log_totalnum % page_per_num == 0)
                {
                    lb_totalNum.Text = (g_history_log_totalnum / page_per_num).ToString();
                }
                else
                {
                    lb_totalNum.Text = ((g_history_log_totalnum / page_per_num) + 1).ToString();
                }
                g_history_data.Clear();
                g_history_log_cur_recv_num = 0;
            }

            if (readinfo[3] == 8)
            {
                g_history_data.Add(readinfo);
                g_history_log_cur_recv_num++;
                
                progressBar.Value = g_history_log_cur_recv_num * 100 / g_history_log_totalnum;
                if (progressBar.Value == 100)
                {
                    btn_sync_historylog.Enabled = true;
                    btn_downlog.Enabled = true;
                    progressBar.Visible = false;
                    show_homepage();
                }
            }

            if (readinfo[3] == 0xa)
            {
                Write_2_dev();
            }

            if (readinfo[3] == 0xb)
            {
                progressBar.Value = 100;
                btn_sync_historylog.Enabled = true;
                btn_downlog.Enabled = true;
                progressBar.Visible = false;
                if (readinfo[4] * 256 + readinfo[5] == g_history_data.Count)
                {
                    MessageBox.Show("日志下载到设备成功！");
                }
                else
                {
                    MessageBox.Show("日志下载到设备失败！");
                }
            }

            if (readinfo[3] == 0xc)
            {
                textBox_can_addr.Text = readinfo[5].ToString("00");
                if ((readinfo[5] <= 1) || (readinfo[5] > 63))
                {
                    MessageBox.Show("设备地址应在2~63范围内");
                }

                textBox_can_type.Text = readinfo[7].ToString("000");
                lb_version.Text = "V " + readinfo[8].ToString() + "." + readinfo[9].ToString();
            }

            if (readinfo[3] == 0x10)
            {
                if (readinfo[4] == 1)
                {
                    int dev_addr = (int)readinfo[5];
                    int dev_type = (int)readinfo[6];
                    if ((dev_type != 154) && (dev_type != 155))
                    {
                        label_selftest_1.Text += " 设备类型不匹配：" + dev_type.ToString();
                        checkBox_self_test_1.Text = "未通过";
                        label_selftest_0.Text += "测试失败，设备类型不匹配，请检查拨码开关";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    label_selftest_1.Text += " 设备类型：" + dev_type.ToString();

                    if ((dev_addr < 2) || (dev_addr > 63))
                    {
                        label_selftest_1.Text += " 设备地址不匹配：" + dev_addr.ToString();
                        checkBox_self_test_1.Text = "未通过";
                        label_selftest_0.Text += "测试失败，设备地址不匹配，设备地址应在2~63之间";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    label_selftest_1.Text += " 设备地址：" + dev_addr.ToString();
                    checkBox_self_test_1.Text = "通过";
                    checkBox_self_test_1.Checked = true;
                    label_selftest_2.Text = "提示： 请在5s内短按 选择 键";
                    timer_self_check.Enabled = true;
                    timer_self_check.Stop();
                    timer_self_check.Start();

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x2, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 2)
                {
                    timer_self_check.Stop();
                    timer_self_check.Start();
                    label_selftest_2.Text = "提示： 请在5s内短按 确认 键";

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x3, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 3)
                {
                    timer_self_check.Stop();
                    timer_self_check.Start();
                    label_selftest_2.Text = "提示： 请在5s内短按 上 键";

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x4, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 4)
                {
                    timer_self_check.Stop();
                    timer_self_check.Start();
                    label_selftest_2.Text = "提示： 请在5s内短按 下 键";

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x5, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 5)
                {
                    timer_self_check.Stop();
                    timer_self_check.Enabled = false;
                    label_selftest_2.Text = "提示： 按键无问题";
                    checkBox_self_test_2.Text = "通过";
                    checkBox_self_test_2.Checked = true;

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x6, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 6)
                {
                    int passwd, root_passwd;
                    passwd = readinfo[5] * 256 + readinfo[6];
                    root_passwd = readinfo[7] * 256 + readinfo[8];
                    if (passwd < 0)
                    {
                        label_selftest_3.Text += " 普通密码不能设置为负数：" + passwd.ToString();
                        checkBox_self_test_3.Text = "未通过";
                        label_selftest_0.Text += "测试失败，普通密码不能设置为负数";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    if (passwd > 9999)
                    {
                        label_selftest_3.Text += " 普通密码不能设置为5位数：" + passwd.ToString();
                        checkBox_self_test_3.Text = "未通过";
                        label_selftest_0.Text += "测试失败，普通密码不能设置为5位数";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    label_selftest_3.Text += " 普通密码:" + passwd.ToString();

                    if (root_passwd < 0)
                    {
                        label_selftest_3.Text += " 超级密码不能设置为负数：" + root_passwd.ToString();
                        checkBox_self_test_3.Text = "未通过";
                        label_selftest_0.Text += "测试失败，超级密码不能设置为负数";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    if (root_passwd > 9999)
                    {
                        label_selftest_3.Text += " 超级密码不能设置为5位数：" + root_passwd.ToString();
                        checkBox_self_test_3.Text = "未通过";
                        label_selftest_0.Text += "测试失败，超级密码不能设置为5位数";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    if (root_passwd == passwd)
                    {
                        label_selftest_3.Text += " 超级密码不能和普通密码相同：" + root_passwd.ToString();
                        checkBox_self_test_3.Text = "未通过";
                        label_selftest_0.Text += "测试失败，超级密码不能和普通密码相同";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    label_selftest_3.Text += " 超级密码:" + root_passwd.ToString();
                    checkBox_self_test_3.Text = "通过";
                    checkBox_self_test_3.Checked = true;

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x7, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 7)
                {
                    int year, month, day, hour, min, sec;
                    year = readinfo[5] + 2000;
                    month = readinfo[6];
                    day = readinfo[7];
                    hour = readinfo[8];
                    min = readinfo[9];
                    sec = readinfo[10];
                    string dev_time_str = year.ToString("0000") + "-" + month.ToString("00") + "-" + day.ToString("00") + " " + hour.ToString("00") + ":" + min.ToString("00") + ":" + sec.ToString("00");

                    DateTime now = DateTime.Now;
                    if ((now.Year != year) || (now.Month != month) || (now.Day != day) || (now.Hour != hour) || (now.Minute != min))
                    {
                        label_selftest_4.Text += " 设备时间要同步。设备时间：" + dev_time_str + " 当前时间：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        checkBox_self_test_4.Text = "未通过";
                        label_selftest_0.Text += "测试失败，设备时间要同步";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    label_selftest_4.Text += " 设备时间：" + dev_time_str + " 当前时间：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    checkBox_self_test_4.Text = "通过";
                    checkBox_self_test_4.Checked = true;

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x8, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 8)
                {
                    if (readinfo[8] == 1)
                    {
                        label_selftest_5.Text += " 擦读写验证失败";
                        checkBox_self_test_5.Text = "未通过";
                        label_selftest_0.Text += "测试失败，擦读写验证失败";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    int erase_time = readinfo[5];
                    int write_time = readinfo[6];
                    int read_time = readinfo[7];
                    label_selftest_5.Text += " 擦读写验证成功, 擦:" + erase_time.ToString() + " ms 写:" + write_time.ToString() + " ms 读:" + read_time.ToString() + " ms";
                    checkBox_self_test_5.Text = "通过";
                    checkBox_self_test_5.Checked = true;

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x9, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 9)
                {
                    if (readinfo[5] == 1)
                    {
                        label_selftest_6.Text += " CANH和GND短路";
                        checkBox_self_test_6.Text = "未通过";
                        label_selftest_0.Text += "测试失败，CANH和GND短路,请排查";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }
                    if (readinfo[5] == 2)
                    {
                        label_selftest_6.Text += " CANL和GND短路";
                        checkBox_self_test_6.Text = "未通过";
                        label_selftest_0.Text += "测试失败，CANL和GND短路,请排查";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }
                    if (readinfo[5] == 3)
                    {
                        label_selftest_6.Text += " CANH和CANL远端不通";
                        checkBox_self_test_6.Text = "未通过";
                        label_selftest_0.Text += "测试失败，CANH和CANL远端不通，有可能没有插好,请排查";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }
                    if (readinfo[5] == 4)
                    {
                        label_selftest_6.Text += " CANH和CANL短路";
                        checkBox_self_test_6.Text = "未通过";
                        label_selftest_0.Text += "测试失败，CANH和CANL短路,请排查";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    if (readinfo[6] == 1)
                    {
                        label_selftest_6.Text += " CAN硬件检测ok，但心跳数据无回复";
                        checkBox_self_test_6.Text = "未通过";
                        label_selftest_0.Text += "测试失败，心跳数据无回复，请检查远端can设备是否打开通讯";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }
                    label_selftest_6.Text += " CAN通信无问题 ";

                    /* 进入下一步 */
                    byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0xa, 0x0, 0x0 };
                    send_modbus_data(sendhex);
                }
                else if (readinfo[4] == 10)
                {
                    if (readinfo[5] == 1)
                    {
                        label_selftest_6.Text += " MODBUS数据无回复";
                        checkBox_self_test_6.Text = "未通过";
                        label_selftest_0.Text += "测试失败，MODBUS数据无回复，请检查排线是否接好";
                        checkBox_self_test_0.Text = "未通过";
                        return;
                    }

                    label_selftest_6.Text += " MODBUS通信无问题 ";
                    checkBox_self_test_6.Text = "通过";
                    checkBox_self_test_6.Checked = true;

                    label_selftest_0.Text += "测试完成，功能正常！";
                    checkBox_self_test_0.Text = "通过";
                    checkBox_self_test_0.Checked = true;
                }
            }
        }
        private void timer_self_check_Tick(object sender, EventArgs e)
        {
            label_selftest_0.Text += "测试失败，请在5s内短按对应按键";
            checkBox_self_test_0.Text = "未通过";
            timer_self_check.Enabled = false;
        }

        //串口接收事件处理
        private void sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                //因为要访问UI资源，所以需要使用invoke方式同步ui
                this.Invoke((EventHandler)(delegate
                {
                    int count = sp.BytesToRead;
                    byte[] buff = new byte[count];
                    sp.Read(buff, 0, count);
                    text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + " recv:";
                    Encoding gb2312 = Encoding.GetEncoding("gb2312");
                    if (g_modbus_mode == 0)
                    {
                        text += gb2312.GetString(buff) + "\r\n";
                    }
                    else
                    {
                        foreach (byte item in buff)
                        {
                            text += item.ToString("X2") + " ";
                        }
                        text += "\r\n";
                        Check_ReadInfo(buff);
                    }
                    textBox_modbus.AppendText(text);
                 }
                   )
                );
            }
            catch (Exception ex)
            {
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message);

            }
        }

        /// <summary>
        /// Initialization of PCAN-Basic components
        /// </summary>
        private void InitializeBasicComponents()
        {
            // Creates the list for received messages
            //
            // Creates the delegate used for message reading
            //
            m_ReadDelegate = new ReadDelegateHandler(ReadMessages);
            // Creates the event used for signalize incomming messages 
            //
            m_ReceiveEvent = new System.Threading.AutoResetEvent(false);
            // Creates an array with all possible non plug-and-play PCAN-Channels
            //
            m_NonPnPHandles = new TPCANHandle[] 
            { 
                PCANBasic.PCAN_ISABUS1,
                PCANBasic.PCAN_ISABUS2,
                PCANBasic.PCAN_ISABUS3,
                PCANBasic.PCAN_ISABUS4,
                PCANBasic.PCAN_ISABUS5,
                PCANBasic.PCAN_ISABUS6,
                PCANBasic.PCAN_ISABUS7,
                PCANBasic.PCAN_ISABUS8,
                PCANBasic.PCAN_DNGBUS1
            };

            // Fills and configures the Data of several comboBox components
            //
            // Channels will be check
            //
            btnHwRefresh_Click(this, new EventArgs());

            // Baudrates 
            //
            cbbBaudrates.SelectedIndex = 3; // 250 K

            // Hardware Type for no plugAndplay hardware
            //
            cbbHwType.SelectedIndex = 0;

            // Interrupt for no plugAndplay hardware
            //
            cbbInterrupt.SelectedIndex = 0;

            // IO Port for no plugAndplay hardware
            //
            cbbIO.SelectedIndex = 0;
            m_Can_Send_MsgId = 1;
            comboBox_candevtype.SelectedIndex = 0;

            // Prepares the PCAN-Basic's debug-Log file
            //b
            ConfigureLogFile();
        }

        /// <summary>
        /// Configures the Debug-Log file of PCAN-Basic
        /// </summary>
        private void ConfigureLogFile()
        {
            UInt32 iBuffer;

            // Sets the mask to catch all events
            //
            iBuffer = PCANBasic.LOG_FUNCTION_ALL;

            // Configures the log file. 
            // NOTE: The Log capability is to be used with the NONEBUS Handle. Other handle than this will 
            // cause the function fail.
            //
            PCANBasic.SetValue(PCANBasic.PCAN_NONEBUS, TPCANParameter.PCAN_LOG_CONFIGURE, ref iBuffer, sizeof(UInt32));
        }

        /// <summary>
        /// Configures the PCAN-Trace file for a PCAN-Basic Channel
        /// </summary>
        private void ConfigureTraceFile()
        {
            UInt32 iBuffer;
            TPCANStatus stsResult;

            // Configure the maximum size of a trace file to 5 megabytes
            //
            iBuffer = 5;
            stsResult = PCANBasic.SetValue(m_PcanHandle, TPCANParameter.PCAN_TRACE_SIZE, ref iBuffer, sizeof(UInt32));
            if (stsResult != TPCANStatus.PCAN_ERROR_OK)
                IncludeTextMessage(GetFormatedError(stsResult));

            // Configure the way how trace files are created: 
            // * Standard name is used
            // * Existing file is ovewritten, 
            // * Only one file is created.
            // * Recording stopts when the file size reaches 5 megabytes.
            //
            iBuffer = PCANBasic.TRACE_FILE_SINGLE | PCANBasic.TRACE_FILE_OVERWRITE;
            stsResult = PCANBasic.SetValue(m_PcanHandle, TPCANParameter.PCAN_TRACE_CONFIGURE, ref iBuffer, sizeof(UInt32));
            if (stsResult != TPCANStatus.PCAN_ERROR_OK)
                IncludeTextMessage(GetFormatedError(stsResult));
        }

        /// <summary>
        /// Help Function used to get an error as text
        /// </summary>
        /// <param name="error">Error code to be translated</param>
        /// <returns>A text with the translated error</returns>
        private string GetFormatedError(TPCANStatus error)
        {
            StringBuilder strTemp;

            // Creates a buffer big enough for a error-text
            //
            strTemp = new StringBuilder(256);
            // Gets the text using the GetErrorText API function
            // If the function success, the translated error is returned. If it fails,
            // a text describing the current error is returned.
            //
            if (PCANBasic.GetErrorText(error, 0, strTemp) != TPCANStatus.PCAN_ERROR_OK)
                return string.Format("An error occurred. Error-code's text (0x{0:X}) couldn't be retrieved", error);
            else
                return strTemp.ToString();
        }

        /// <summary>
        /// Includes a new line of text into the information Listview
        /// </summary>
        /// <param name="strMsg">Text to be included</param>
        private void IncludeTextMessage(string strMsg)
        {
            lbxInfo.Items.Add(strMsg);
            lbxInfo.SelectedIndex = lbxInfo.Items.Count - 1;
        }

        private void IncludeRecvMessage(string strMsg)
        {
            msgBox.Items.Add(strMsg);
            msgBox.SelectedIndex = msgBox.Items.Count - 1;
        }

        /// <summary>
        /// Gets the current status of the PCAN-Basic message filter
        /// </summary>
        /// <param name="status">Buffer to retrieve the filter status</param>
        /// <returns>If calling the function was successfull or not</returns>
        private bool GetFilterStatus(out uint status)
        {
            TPCANStatus stsResult;

            // Tries to get the sttaus of the filter for the current connected hardware
            //
            stsResult = PCANBasic.GetValue(m_PcanHandle, TPCANParameter.PCAN_MESSAGE_FILTER, out status, sizeof(UInt32));

            // If it fails, a error message is shown
            //
            if (stsResult != TPCANStatus.PCAN_ERROR_OK)
            {
                MessageBox.Show(GetFormatedError(stsResult));
                return false;
            }
            return true;
        }   

        /// <summary>
        /// Activates/deaactivates the different controls of the main-form according
        /// with the current connection status
        /// </summary>
        /// <param name="bConnected">Current status. True if connected, false otherwise</param>
        private void SetConnectionStatus(bool bConnected)
        {
            // Buttons
            //
            btnInit.Enabled = !bConnected;
            btnRelease.Enabled = bConnected;    
            btnGetVersions.Enabled = bConnected;
            btnHwRefresh.Enabled = !bConnected;
            btnStatus.Enabled = bConnected;
            btnReset.Enabled = bConnected;

            // ComboBoxs
            //
            cbbChannel.Enabled = !bConnected;               
            cbbBaudrates.Enabled = !bConnected;
            cbbHwType.Enabled = !bConnected;
            cbbIO.Enabled = !bConnected;
            cbbInterrupt.Enabled = !bConnected;


            // Hardware configuration and read mode
            //
            if (!bConnected)
                cbbChannel_SelectedIndexChanged(this, new EventArgs());
            else
                rdbTimer_CheckedChanged(this, new EventArgs());

            // Display messages in grid
            //
        }

        /// <summary>
        /// Gets the formated text for a PCAN-Basic channel handle
        /// </summary>
        /// <param name="handle">PCAN-Basic Handle to format</param>
        /// <param name="isFD">If the channel is FD capable</param>
        /// <returns>The formatted text for a channel</returns>
        private string FormatChannelName(TPCANHandle handle, bool isFD)
        {
            TPCANDevice devDevice;
            byte byChannel;

            // Gets the owner device and channel for a 
            // PCAN-Basic handle
            //
            if (handle < 0x100)
            {
                devDevice = (TPCANDevice)(handle >> 4);
                byChannel = (byte)(handle & 0xF);
            }
            else
            {
                devDevice = (TPCANDevice)(handle >> 8);
                byChannel = (byte)(handle & 0xFF);
            }

            // Constructs the PCAN-Basic Channel name and return it
            //
            if (isFD)
                return string.Format("{0}:FD {1} ({2:X2}h)", devDevice, byChannel, handle);
            else
                return string.Format("{0} {1} ({2:X2}h)", devDevice, byChannel, handle);
        }

        /// <summary>
        /// Gets the formated text for a PCAN-Basic channel handle
        /// </summary>
        /// <param name="handle">PCAN-Basic Handle to format</param>
        /// <returns>The formatted text for a channel</returns>
        private string FormatChannelName(TPCANHandle handle)
        {
            return FormatChannelName(handle, false);
        }
#endregion

        #region Message-proccessing functions
        /// <summary>
        /// Display CAN messages in the Message-ListView
        /// </summary>
        private byte[] m_Recv_Last_Data = new byte[40];  // 接收数据，每包8字节的话能接收5包
        private int[] m_Recv_Last_Id = new int[5];
        private int[] m_Recv_Last_Len = new int[5];
        private byte m_Recv_Last_Index = 0;

        private void RecvProtolol_ACK(int msg_id, int FuncCode)
        {
            TPCANMsg CANMsg;
            TPCANId CANId;

            // We create a TPCANMsg message structure 
            //
            CANMsg = new TPCANMsg();
            CANMsg.DATA = new byte[8];

            // We configurate the Message.  The ID,
            // Length of the Data, Message Type
            // and the data
            //
            CANId.msgtype = 1;  // 0 请求帧 1 应答帧
            CANId.dst_addr = 0;  // 1 目标地址
            if (FuncCode == 0x11) {
                CANId.priority = 1;  // 优先级
            } else {
                CANId.priority = 3;
            }
            CANId.src_addr = 1;  // 2 源地址
            CANId.msg_id = (byte)msg_id;  // 报文编号
            CANId.group_id = 0;  // 分组编号

            CANMsg.ID = CANId.ToUInt32();
            CANMsg.LEN = 1;
            CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_EXTENDED;
            CANMsg.DATA[0] = (byte)FuncCode;    
            // If a remote frame will be sent, the data bytes are not important.
            //
                // We get so much data as the Len of the message
                //

            // The message is sent to the configured hardware
            //
            PCANBasic.Write(m_PcanHandle, ref CANMsg);
            DateTime now = DateTime.Now; // 获取当前时间
            IncludeTextMessage(now.ToString() + " Send: " + CANMsg.ID.ToString("X8") + " len:" + CANMsg.LEN.ToString() + " data:" + BitConverter.ToString(CANMsg.DATA, 0, CANMsg.LEN));
            return;
        }

        private void RecvProtolol(TPCANMsg CANMsg, TPCANTimestamp CANTimeStamp)
        {
            TPCANId CANId = new TPCANId();
            DateTime now = DateTime.Now; // 获取当前时间
            int event_id;

            if ((CANMsg.LEN == 0) || (CANMsg.LEN > 8))
            {
                IncludeRecvMessage("Recv Invalid message length");
                return;
            }

            CANId.FromUInt32(CANMsg.ID, ref CANId);
            if ((CANId.group_id > 0) && (CANId.group_id < 5))
            {
                m_Recv_Last_Id[CANId.group_id] = (int)CANMsg.ID;
                m_Recv_Last_Len[CANId.group_id] = (int)CANMsg.LEN;
                for (int i = 0; i < CANMsg.LEN; i++) {
                    m_Recv_Last_Data[(CANId.group_id - 1) * 8 + i] = CANMsg.DATA[i];
                }
                m_Recv_Last_Index++;
                return;
            }

            if (CANId.group_id == 0) {
                m_Recv_Last_Id[m_Recv_Last_Index] = (int)CANMsg.ID;
                m_Recv_Last_Len[m_Recv_Last_Index] = (int)CANMsg.LEN;
                for (int i = 0; i < CANMsg.LEN; i++) {
                    m_Recv_Last_Data[m_Recv_Last_Index * 8 + i] = CANMsg.DATA[i];
                }
            }

            /* 应答帧 */
            if (CANId.msgtype == 1) {
                if (m_Recv_Last_Data[0] == 5) {
                    IncludeRecvMessage(now.ToString() + " >>>下发紧急事件应答帧(05)");
                } else if (m_Recv_Last_Data[0] == 6) {
                    IncludeRecvMessage(now.ToString() + " >>>下发一般事件应答帧(06)");
                } else if (m_Recv_Last_Data[0] == 41) {
                    if (m_Recv_Last_Index > 2) {
                        event_id = m_Recv_Last_Data[8] * 256 + m_Recv_Last_Data[7];
                        IncludeRecvMessage(now.ToString() + " >>>查设备当前事件应答帧(41) eventid: " + Get_Event_DesInfo(event_id) + 
                                           " status:" + m_Recv_Last_Data[10].ToString("X2") + m_Recv_Last_Data[9].ToString("X2"));
                    }
                }
            }

            /* 请求帧 */    
            if (CANId.msgtype == 0) {
                event_id = m_Recv_Last_Data[8] * 256 + m_Recv_Last_Data[7];
                if (m_Recv_Last_Data[0] == 0x11) {
                    IncludeRecvMessage(now.ToString() + " >>>上报紧急事件帧(17) eventid:" + Get_Event_DesInfo(event_id));
                    RecvProtolol_ACK((int)CANId.msg_id, 0x11);
                    IncludeRecvMessage(now.ToString() + " >>>应答紧急事件帧(17) eventid:" + Get_Event_DesInfo(event_id));
                } else if (m_Recv_Last_Data[0] == 0x12) {
                    IncludeRecvMessage(now.ToString() + " >>>上报一般事件帧(18) eventid:" + Get_Event_DesInfo(event_id));
                    RecvProtolol_ACK((int)CANId.msg_id, 0x12);
                    IncludeRecvMessage(now.ToString() + " >>>应答一般事件帧(18) eventid:" + Get_Event_DesInfo(event_id));
                } else if (m_Recv_Last_Data[0] == 0x14) {
                    IncludeRecvMessage(now.ToString() + " >>>上报心跳帧(20)");
                    RecvProtolol_ACK((int)CANId.msg_id, 0x14);
                    IncludeRecvMessage(now.ToString() + " >>>应答心跳帧(20)");
                }
            }

            /* 清除数据缓存 */
            Array.Clear(m_Recv_Last_Id, 0, m_Recv_Last_Id.Length); // 所有元素变为0
            Array.Clear(m_Recv_Last_Len, 0, m_Recv_Last_Len.Length); // 所有元素变为0
            Array.Clear(m_Recv_Last_Data, 0, m_Recv_Last_Data.Length); // 所有元素变为0
            m_Recv_Last_Index = 0;  
            return;
        }
        /// <summary>
        /// Function for reading CAN messages on normal CAN devices
        /// </summary>
        /// <returns>A TPCANStatus error code</returns>
        private TPCANStatus ReadMessage()
        {
            TPCANMsg CANMsg;
            TPCANTimestamp CANTimeStamp;
            TPCANStatus stsResult;

            // We execute the "Read" function of the PCANBasic                
            //
            stsResult = PCANBasic.Read(m_PcanHandle, out CANMsg, out CANTimeStamp);
            if (stsResult != TPCANStatus.PCAN_ERROR_QRCVEMPTY) {
                // We process the received message
                //
                DateTime now = DateTime.Now; // 获取当前时间
                if (CANMsg.LEN > 0) {
                    IncludeTextMessage(now.ToString() + " Recv: " + CANMsg.ID.ToString("X8") + " len:" + CANMsg.LEN.ToString() + " data:" + BitConverter.ToString(CANMsg.DATA, 0, CANMsg.LEN));
                    RecvProtolol(CANMsg, CANTimeStamp);
                }
            }

            return stsResult;
        }

        /// <summary>
        /// Function for reading PCAN-Basic messages
        /// </summary>
        private void ReadMessages()
        {
            TPCANStatus stsResult;

            // We read at least one time the queue looking for messages.
            // If a message is found, we look again trying to find more.
            // If the queue is empty or an error occurr, we get out from
            // the dowhile statement.
            //			
            do
            {
                stsResult = ReadMessage();
                if (stsResult == TPCANStatus.PCAN_ERROR_ILLOPERATION)
                    break;
            } while (btnRelease.Enabled && (!Convert.ToBoolean(stsResult & TPCANStatus.PCAN_ERROR_QRCVEMPTY)));
        }
        #endregion

        #region Event Handlers
        #region Form event-handlers
        /// <summary>
        /// Consturctor
        /// </summary>
        public Form1()
        {
            // Initializes Form's component
            //
            InitializeComponent();
            // Initializes specific components
            //
            InitializeBasicComponents();

            InitializeTty();
        }

        /// <summary>
        /// Form-Closing Function / Finish function
        /// </summary>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Releases the used PCAN-Basic channel
            //
            if (btnRelease.Enabled)
                btnRelease_Click(this, new EventArgs());
        }
        #endregion

        #region ComboBox event-handlers
        private void cbbChannel_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool bNonPnP;
            string strTemp;

            // Get the handle fromt he text being shown
            //
            strTemp = cbbChannel.Text;
            strTemp = strTemp.Substring(strTemp.IndexOf('(') + 1, 3);

            strTemp = strTemp.Replace('h', ' ').Trim(' ');

            // Determines if the handle belong to a No Plug&Play hardware 
            //
            m_PcanHandle = Convert.ToUInt16(strTemp, 16);
            bNonPnP = m_PcanHandle <= PCANBasic.PCAN_DNGBUS1;
            // Activates/deactivates configuration controls according with the 
            // kind of hardware
            //
            cbbHwType.Enabled = bNonPnP;
            cbbIO.Enabled = bNonPnP;
            cbbInterrupt.Enabled = bNonPnP;
        }

        private void cbbBaudrates_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Saves the current selected baudrate register code
            //
            switch (cbbBaudrates.SelectedIndex)
            {
                case 0:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_1M;
                    break;
                case 1:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_800K;
                    break;
                case 2:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_500K;
                    break;
                case 3:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_250K;
                    break;
                case 4:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_125K;
                    break;
                case 5:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_100K;
                    break;
                case 6:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_95K;
                    break;
                case 7:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_83K;
                    break;
                case 8:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_50K;
                    break;
                case 9:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_47K;
                    break;
                case 10:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_33K;
                    break;
                case 11:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_20K;
                    break;
                case 12:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_10K;
                    break;
                case 13:
                    m_Baudrate = TPCANBaudrate.PCAN_BAUD_5K;
                    break;
            }
        }

        private void cbbHwType_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Saves the current type for a no-Plug&Play hardware
            //
            switch (cbbHwType.SelectedIndex)
            {
                case 0:
                    m_HwType = TPCANType.PCAN_TYPE_ISA;
                    break;
                case 1:
                    m_HwType = TPCANType.PCAN_TYPE_ISA_SJA;
                    break;
                case 2:
                    m_HwType = TPCANType.PCAN_TYPE_ISA_PHYTEC;
                    break;
                case 3:
                    m_HwType = TPCANType.PCAN_TYPE_DNG;
                    break;
                case 4:
                    m_HwType = TPCANType.PCAN_TYPE_DNG_EPP;
                    break;
                case 5:
                    m_HwType = TPCANType.PCAN_TYPE_DNG_SJA;
                    break;
                case 6:
                    m_HwType = TPCANType.PCAN_TYPE_DNG_SJA_EPP;
                    break;
            }
        }
        #endregion

        #region Button event-handlers
        private void btnHwRefresh_Click(object sender, EventArgs e)
        {
            TPCANStatus stsResult;
            uint iChannelsCount;
            bool bIsFD;

            // Clears the Channel comboBox and fill it again with 
            // the PCAN-Basic handles for no-Plug&Play hardware and
            // the detected Plug&Play hardware
            //
            cbbChannel.Items.Clear();
            try
            {
                // Includes all no-Plug&Play Handles
                for (int i = 0; i < m_NonPnPHandles.Length; i++)                    
                    cbbChannel.Items.Add(FormatChannelName(m_NonPnPHandles[i]));

                // Checks for available Plug&Play channels
                //
                stsResult = PCANBasic.GetValue(PCANBasic.PCAN_NONEBUS, TPCANParameter.PCAN_ATTACHED_CHANNELS_COUNT, out iChannelsCount, sizeof(uint));
                if (stsResult == TPCANStatus.PCAN_ERROR_OK)
                {
                    TPCANChannelInformation[] info = new TPCANChannelInformation[iChannelsCount];

                    stsResult = PCANBasic.GetValue(PCANBasic.PCAN_NONEBUS, TPCANParameter.PCAN_ATTACHED_CHANNELS, info);
                    if (stsResult == TPCANStatus.PCAN_ERROR_OK)
                        // Include only connectable channels
                        //
                        foreach (TPCANChannelInformation channel in info)
                            if ((channel.channel_condition & PCANBasic.PCAN_CHANNEL_AVAILABLE) == PCANBasic.PCAN_CHANNEL_AVAILABLE)
                            {
                                bIsFD = (channel.device_features & PCANBasic.FEATURE_FD_CAPABLE) == PCANBasic.FEATURE_FD_CAPABLE;
                                cbbChannel.Items.Add(FormatChannelName(channel.channel_handle, bIsFD));
                            }
                }

                cbbChannel.SelectedIndex = cbbChannel.Items.Count - 1;
                btnInit.Enabled = cbbChannel.Items.Count > 0;

                if (stsResult != TPCANStatus.PCAN_ERROR_OK)
                    MessageBox.Show(GetFormatedError(stsResult));
            }
            catch(DllNotFoundException)
            {
                MessageBox.Show("Unable to find the library: PCANBasic.dll !", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.Exit(-1);
            }
        }

        private void btnInit_Click(object sender, EventArgs e)
        {
            TPCANStatus stsResult;

            // Connects a selected PCAN-Basic channel
            //
            stsResult = PCANBasic.Initialize(
                m_PcanHandle,
                m_Baudrate,
                m_HwType,
                Convert.ToUInt32(cbbIO.Text, 16),
                Convert.ToUInt16(cbbInterrupt.Text));

            if (stsResult != TPCANStatus.PCAN_ERROR_OK)
                if (stsResult != TPCANStatus.PCAN_ERROR_CAUTION)
                    MessageBox.Show(GetFormatedError(stsResult));
                else
                {
                    IncludeTextMessage("******************************************************");
                    IncludeTextMessage("The bitrate being used is different than the given one");
                    IncludeTextMessage("******************************************************");
                    stsResult = TPCANStatus.PCAN_ERROR_OK;
                }
            else
                // Prepares the PCAN-Basic's PCAN-Trace file
                //
                ConfigureTraceFile();

            // Sets the connection status of the main-form
            //
            SetConnectionStatus(stsResult == TPCANStatus.PCAN_ERROR_OK);
        }

        private void btnRelease_Click(object sender, EventArgs e)
        {
            // Releases a current connected PCAN-Basic channel
            //
            PCANBasic.Uninitialize(m_PcanHandle);
            tmrRead.Enabled = false;
            // Sets the connection status of the main-form
            //
            SetConnectionStatus(false);
        }

        private void btnGetVersions_Click(object sender, EventArgs e)
        {
            TPCANStatus stsResult;
            StringBuilder strTemp;
            string[] strArrayVersion;

            strTemp = new StringBuilder(256);

            // We get the vesion of the PCAN-Basic API
            //
            stsResult = PCANBasic.GetValue(PCANBasic.PCAN_NONEBUS, TPCANParameter.PCAN_API_VERSION, strTemp, 256);
            if (stsResult == TPCANStatus.PCAN_ERROR_OK)
            {
                IncludeTextMessage("API Version: " + strTemp.ToString());
                
                // We get the version of the firmware on the device
                //
                stsResult = PCANBasic.GetValue(m_PcanHandle, TPCANParameter.PCAN_FIRMWARE_VERSION, strTemp, 256);
                if (stsResult == TPCANStatus.PCAN_ERROR_OK)
                    IncludeTextMessage("Firmare Version: " + strTemp.ToString());

                // We get the driver version of the channel being used
                //
                stsResult = PCANBasic.GetValue(m_PcanHandle, TPCANParameter.PCAN_CHANNEL_VERSION, strTemp, 256);
                if (stsResult == TPCANStatus.PCAN_ERROR_OK)
                {
                    // Because this information contains line control characters (several lines)
                    // we split this also in several entries in the Information List-Box
                    //
                    strArrayVersion = strTemp.ToString().Split(new char[] { '\n' });
                    IncludeTextMessage("Channel/Driver Version: ");
                    for (int i = 0; i < strArrayVersion.Length; i++)
                        IncludeTextMessage("     * " + strArrayVersion[i]);
                }               
            }

            // If an error ccurred, a message is shown
            //
            if (stsResult != TPCANStatus.PCAN_ERROR_OK)
                MessageBox.Show(GetFormatedError(stsResult));
        }

        private void btnMsgClear_Click(object sender, EventArgs e)
        {
            // The information contained in the messages List-View
            // is cleared
            //
            msgBox.Items.Clear();   
        }

        private void btnInfoClear_Click(object sender, EventArgs e)
        {
            // The information contained in the Information List-Box 
            // is cleared
            //
            lbxInfo.Items.Clear();
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            TPCANStatus stsResult;

            // Resets the receive and transmit queues of a PCAN Channel.
            //
            stsResult = PCANBasic.Reset(m_PcanHandle);

            // If it fails, a error message is shown
            //
            if (stsResult != TPCANStatus.PCAN_ERROR_OK)
                MessageBox.Show(GetFormatedError(stsResult));
            else
                IncludeTextMessage("Receive and transmit queues successfully reset");
        }

        private void btnStatus_Click(object sender, EventArgs e)
        {
            TPCANStatus stsResult;
            String errorName;

            // Gets the current BUS status of a PCAN Channel.
            //
            stsResult = PCANBasic.GetStatus(m_PcanHandle);

            // Switch On Error Name
            //
            switch (stsResult)
            {
                case TPCANStatus.PCAN_ERROR_INITIALIZE:
                    errorName = "PCAN_ERROR_INITIALIZE";
                    break;

                case TPCANStatus.PCAN_ERROR_BUSLIGHT:
                    errorName = "PCAN_ERROR_BUSLIGHT";
                    break;

                case TPCANStatus.PCAN_ERROR_BUSHEAVY: // TPCANStatus.PCAN_ERROR_BUSWARNING
                    errorName = "PCAN_ERROR_BUSHEAVY";
                    break;

                case TPCANStatus.PCAN_ERROR_BUSPASSIVE: 
                    errorName = "PCAN_ERROR_BUSPASSIVE";
                    break;
                
                case TPCANStatus.PCAN_ERROR_BUSOFF:
                    errorName = "PCAN_ERROR_BUSOFF";
                    break;

                case TPCANStatus.PCAN_ERROR_OK:
                    errorName = "PCAN_ERROR_OK";
                    break;

                default:
                    errorName = "See Documentation";
                    break;
            }

            // Display Message
            //
            IncludeTextMessage(String.Format("Status: {0} (0x{1:X}h)", errorName, stsResult));
        }
        #endregion

        #region Timer event-handler
        private void tmrRead_Tick(object sender, EventArgs e)
        { 
            // Checks if in the receive-queue are currently messages for read
            // 
            ReadMessages();
        }

        #endregion

        #region Message List-View event-handler
        #endregion

        #region Information List-Box event-handler
        private void lbxInfo_DoubleClick(object sender, EventArgs e)
        {
            // Clears the content of the Information List-Box
            //
            btnInfoClear_Click(this, new EventArgs());
        }
        #endregion

        #region Textbox event handlers        private void txtID_KeyPress(object sender, KeyPressEventArgs e)

        #endregion

        #region Radio- and Check- Buttons event-handlers

        private void rdbTimer_CheckedChanged(object sender, EventArgs e)
        {
            if (!btnRelease.Enabled)
                return;

            // According with the kind of reading, a timer, a thread or a button will be enabled
            //
                // Abort Read Thread if it exists
                //

                // Enable Timer
                //
                tmrRead.Enabled = btnRelease.Enabled;
        }

        #endregion

        #endregion

#endregion

        private void send1_Click(object sender, EventArgs e)
        {
            TPCANMsg CANMsg;
            TPCANId CANId;

            // We create a TPCANMsg message structure 
            //
            CANMsg = new TPCANMsg();
            CANMsg.DATA = new byte[8];

            // We configurate the Message.  The ID,
            // Length of the Data, Message Type
            // and the data
            //
            CANId.msgtype = 0;  // 0 请求帧 1 应答帧
            CANId.dst_addr = 1;  // 1 目标地址
            CANId.priority = 1;  // 优先级
            CANId.src_addr = 2;  // 2 源地址
            CANId.msg_id = 0x01;  // 报文编号
            CANId.group_id = 0;  // 分组编号

            CANMsg.ID = CANId.ToUInt32();
            CANMsg.LEN = 8;
            CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_EXTENDED;
            // If a remote frame will be sent, the data bytes are not important.
            //
                // We get so much data as the Len of the message
                //

            // The message is sent to the configured hardware
            //
            PCANBasic.Write(m_PcanHandle, ref CANMsg);
            return;
        }

        /* eventid 事件id， FuncCode 0x5 通告紧急事件  0x6 通告一般事件  */
        private void Can_Send_Data(int eventid, int FuncCode)
        {
            TPCANId CANId;
            TPCANMsg CANMsg;
            byte priority = 3;

            if (FuncCode == 5) {
                priority = 1;   // 紧急事件优先级调高
            }

            // We create a TPCANMsg message structure 
            //
            CANMsg = new TPCANMsg();
            CANMsg.DATA = new byte[8];
            DateTime now = DateTime.Now; // 获取当前时间

            int can_dev_addr = Convert.ToInt32(textBox_candevaddr.Text);

            int can_dev_type = 0;
            if (comboBox_candevtype.SelectedIndex == 0)
            {
                can_dev_type = 154;
            }
            else if (comboBox_candevtype.SelectedIndex == 1)
            {
                can_dev_type = 155;
            }
            if ((FuncCode == 5) || (FuncCode == 6))
            {
                CANId.msgtype = 0;  // 0 请求帧 1 应答帧
                CANId.dst_addr = (byte)can_dev_addr;  // 1 目标地址
                CANId.priority = priority;  // 优先级
                CANId.src_addr = 1;  //  源地址
                CANId.msg_id = m_Can_Send_MsgId;  // 报文编号
                CANId.group_id = 1;  // 分组编号


                CANMsg.ID = CANId.ToUInt32();
                CANMsg.LEN = 8;
                CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_EXTENDED;
                CANMsg.DATA[0] = (byte)FuncCode;     //紧急报文
                CANMsg.DATA[1] = 0;     //控制器编号
                CANMsg.DATA[2] = 0;     //单元编号
                CANMsg.DATA[3] = 0;     //设备编号
                CANMsg.DATA[4] = 0;     //通道编号
                CANMsg.DATA[5] = (byte)(can_dev_type & 0xff);     //设备类型代码0
                CANMsg.DATA[6] = (byte)((can_dev_type >> 8) & 0xff);     //设备类型代码1
                CANMsg.DATA[7] = (byte)(eventid & 0xff);     //事件类型代码0
                PCANBasic.Write(m_PcanHandle, ref CANMsg);
                IncludeTextMessage(now.ToString() + " Send: " + CANMsg.ID.ToString("X8") + " len:" + CANMsg.LEN.ToString() + " data:" + BitConverter.ToString(CANMsg.DATA, 0, CANMsg.LEN));
                Thread.Sleep(20);

                CANId.group_id = 2; // 分组编号
                CANMsg.ID = CANId.ToUInt32();
                CANMsg.DATA[0] = (byte)((eventid >> 8) & 0xff);     //事件类型代码1
                CANMsg.DATA[1] = 0;     //状态代码0
                CANMsg.DATA[2] = 0;     //状态代码1
                CANMsg.DATA[3] = (byte)(now.Year - 2000);     //年
                CANMsg.DATA[4] = (byte)now.Month;     //月
                CANMsg.DATA[5] = (byte)now.Day;     //日
                CANMsg.DATA[6] = (byte)now.Hour;     //时
                CANMsg.DATA[7] = (byte)now.Minute;     //分   
                PCANBasic.Write(m_PcanHandle, ref CANMsg);
                IncludeTextMessage(now.ToString() + " Send: " + CANMsg.ID.ToString("X8") + " len:" + CANMsg.LEN.ToString() + " data:" + BitConverter.ToString(CANMsg.DATA, 0, CANMsg.LEN));
                Thread.Sleep(20);

                CANId.group_id = 3; // 分组编号
                CANMsg.ID = CANId.ToUInt32();
                CANMsg.LEN = 1;
                CANMsg.DATA[0] = (byte)now.Second;     //秒   
                PCANBasic.Write(m_PcanHandle, ref CANMsg);
                IncludeTextMessage(now.ToString() + " Send: " + CANMsg.ID.ToString("X8") + " len:" + CANMsg.LEN.ToString() + " data:" + BitConverter.ToString(CANMsg.DATA, 0, CANMsg.LEN));
                Thread.Sleep(20);

                CANId.group_id = 0; // 分组编号
                CANMsg.ID = CANId.ToUInt32();
                CANMsg.LEN = 2;
                CANMsg.DATA[0] = 0xf;
                CANMsg.DATA[1] = 0;
                PCANBasic.Write(m_PcanHandle, ref CANMsg);
                IncludeTextMessage(now.ToString() + " Send: " + CANMsg.ID.ToString("X8") + " len:" + CANMsg.LEN.ToString() + " data:" + BitConverter.ToString(CANMsg.DATA, 0, CANMsg.LEN));

                if (FuncCode == 0x5)
                {
                    IncludeRecvMessage(now.ToString() + " >>>下发紧急事件(05)" + "  eventid: " + Get_Event_DesInfo(eventid) + "  msgid: " + m_Can_Send_MsgId.ToString());
                }
                else if (FuncCode == 0x6)
                {
                    IncludeRecvMessage(now.ToString() + " >>>下发一般事件(06)" + "   eventid: " + Get_Event_DesInfo(eventid) + "  msgid: " + m_Can_Send_MsgId.ToString());
                }

            }
            else if (FuncCode == 41)
            {
                CANId.msgtype = 0;  // 0 请求帧 1 应答帧
                CANId.dst_addr = (byte)can_dev_addr;  // 1 目标地址
                CANId.priority = 2;  // 优先级
                CANId.src_addr = 1;  //  源地址
                CANId.msg_id = m_Can_Send_MsgId;  // 报文编号
                CANId.group_id = 0;  // 分组编号


                CANMsg.ID = CANId.ToUInt32();
                CANMsg.LEN = 4;
                CANMsg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_EXTENDED;
                CANMsg.DATA[0] = (byte)FuncCode;     //紧急报文
                CANMsg.DATA[1] = 0;     //控制器编号
                CANMsg.DATA[2] = (byte)(eventid & 0xff);     //事件类型代码0
                CANMsg.DATA[3] = (byte)((eventid >> 8) & 0xff);     //事件类型代码0
                PCANBasic.Write(m_PcanHandle, ref CANMsg);
                IncludeTextMessage(now.ToString() + " Send: " + CANMsg.ID.ToString("X8") + " len:" + CANMsg.LEN.ToString() + " data:" + BitConverter.ToString(CANMsg.DATA, 0, CANMsg.LEN));
                IncludeRecvMessage(now.ToString() + " >>>下发查设备当前事件(41)" + "   eventid: " + Get_Event_DesInfo(eventid) + "  msgid: " + m_Can_Send_MsgId.ToString());
            }

            m_Can_Send_MsgId++;
            if (m_Can_Send_MsgId > 63) {
                m_Can_Send_MsgId = 1;
            }

        }

        private void B_cmd_send_Click(object sender, EventArgs e)
        {
            if (textBox_candevaddr.Text == "")
            {
                MessageBox.Show("请输入设备地址");
                return;
            }

            int can_dev_addr = Convert.ToInt32(textBox_candevaddr.Text);
            if ((can_dev_addr > 63) || (can_dev_addr < 0))
            {
                MessageBox.Show("设备地址范围应为0~63");
                return;
            }

            if (can_dev_addr == 1)
            {
                MessageBox.Show("地址1为报警器专用");
                return;
            }

            switch (B_comboBox.SelectedIndex) {
                case 0:
                    Can_Send_Data(20, 5);     //自动启动
                    break;
                case 1:
                    Can_Send_Data(45, 5);     //卷帘半降
                    break;
                case 2:
                    Can_Send_Data(46, 5);     //卷帘全降
                    break;
                case 6:
                    Can_Send_Data(57, 6);     //取消半降
                    break;
                case 7:
                    Can_Send_Data(58, 6);     //取消全降
                    break;
            }
        }

        private void C_cmd_send_Click(object sender, EventArgs e)
        {
            if (textBox_candevaddr.Text == "")
            {
                MessageBox.Show("请输入设备地址");
                return;
            }

            int can_dev_addr = Convert.ToInt32(textBox_candevaddr.Text);
            if ((can_dev_addr > 63) || (can_dev_addr < 0))
            {
                MessageBox.Show("设备地址范围应为0~63");
                return;
            }

            if (can_dev_addr == 1)
            {
                MessageBox.Show("地址1为报警器专用");
                return;
            }

            switch (C_comboBox.SelectedIndex) {
                case 0:
                    Can_Send_Data(23, 41);     //联动启动
                    break;
                case 1:
                    Can_Send_Data(259, 41);     //手动上行
                    break;
                case 2:
                    Can_Send_Data(260, 41);     //手动下行
                    break;
                case 3:
                    Can_Send_Data(256, 41);     //上位
                    break;
                case 4:
                    Can_Send_Data(257, 41);     //中位
                    break;
                case 5:
                    Can_Send_Data(258, 41);     //下位
                    break;
                case 6:
                    Can_Send_Data(29, 41);     //停止
                    break;
                case 7:
                    Can_Send_Data(82, 41);     //主电故障
                    break;
                case 8:
                    Can_Send_Data(83, 41);     //备电故障
                    break;
                case 9:
                    Can_Send_Data(86, 41);     //部件故障
                    break;
                case 10:
                    Can_Send_Data(87, 41);     //线路故障
                    break;
                case 11:
                    Can_Send_Data(100, 41);     //故障恢复
                    break;
                case 12:
                    Can_Send_Data(21, 41);     //手动启动
                    break;
                case 13:
                    Can_Send_Data(81, 41);     //通信故障
                    break;            
            }
        }

        private void 报警器模拟ToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void groupBox6_Enter(object sender, EventArgs e)
        {

        }

        private void label4_Click(object sender, EventArgs e)
        {

        }

        private void btnOpentty_Click(object sender, EventArgs e)
        {
            try
            {
                if (!sp.IsOpen)
                {
                    sp.Open();
                    btnOpentty.Enabled = false;
                    btnCloseTty.Enabled = true;
                    textBox_modbus.Focus();
                }
                else
                {
                    sp.Close();
                    btnOpentty.Enabled = true;
                    btnCloseTty.Enabled = false;
                    textBox_modbus.Focus();
                }
            }
            catch (Exception ex)
            {
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message);

            }
        }

        private void btnCloseTty_Click(object sender, EventArgs e)
        {
            try
            {
                if (!sp.IsOpen)
                {
                    sp.Open();
                    btnOpentty.Enabled = false;
                    btnCloseTty.Enabled = true;
                    textBox_modbus.Focus();
                }
                else
                {
                    sp.Close();
                    btnOpentty.Enabled = true;
                    btnCloseTty.Enabled = false;
                    textBox_modbus.Focus();
                }
            }
            catch (Exception ex)
            {
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message);

            }
        }
        string sendtext;
        private void send_modbus_data(byte[] senddata)
        {
            try
            {
                if (sp.IsOpen)
                {
                    CRC16.CRC_16 crcfunc = new CRC16.CRC_16();
                    Byte[] crc = crcfunc.getcrc(senddata, 0, senddata.Length - 2);
                    senddata[senddata.Length - 1] = crc[0];
                    senddata[senddata.Length - 2] = crc[1];
                    sp.Write(senddata, 0, senddata.Length);
                    sendtext = text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + " send:"; ;
                    foreach (byte item in senddata)
                    {
                        sendtext += item.ToString("X2") + " ";
                    }
                    sendtext += "\r\n";
                    textBox_modbus.AppendText(sendtext);
                }
            }
            catch (Exception ex)
            {
                //响铃并显示异常给用户
                System.Media.SystemSounds.Beep.Play();
                MessageBox.Show(ex.Message);
            }
            return;
        }

        private void cbbBaud_SelectedIndexChanged(object sender, EventArgs e)
        {
            sp.BaudRate = Convert.ToInt32(cbbBaud.Items[cbbBaud.SelectedIndex].ToString());
            sp.DataBits = 8;
            sp.StopBits = (StopBits)1;
            sp.Parity = 0;
        }

        private void cbbPort_SelectedIndexChanged(object sender, EventArgs e)
        {
            sp.PortName = cbbPort.Items[cbbPort.SelectedIndex].ToString();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void ttybox_TextChanged(object sender, EventArgs e)
        {

        }

        private void 报警器模拟ToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            pCan.Visible = true;
            pModbus.Visible = false;
        }

        private void 串口调试ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
        }

        private void bt_cmdmode_Click(object sender, EventArgs e)
        {
            byte[] sendhex = { 0x01, 0x05, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0 };
            g_modbus_mode = 1;
            send_modbus_data(sendhex);
        }

        private void bt_printmode_Click(object sender, EventArgs e)
        {
            byte[] sendhex = { 0x01, 0x05, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0 };
            g_modbus_mode = 0;
            send_modbus_data(sendhex);
        }

        private void bt_getpasswd_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            byte[] sendhex = { 0x01, 0x01, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex);
        }

        private void bt_gettime_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            byte[] sendhex = { 0x01, 0x01, 0x0, 0x4, 0x0, 0x3, 0x0, 0x0 };
            send_modbus_data(sendhex);
            text_curtime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }

        private void bt_clear_modbus_txt_Click(object sender, EventArgs e)
        {
            textBox_modbus.Clear();
        }

        private void bt_setuserpasswd_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            byte[] sendhex = { 0x01, 0x05, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0 };
            if (textpasswd.Text == "")
            {
                MessageBox.Show("请输入密码");
                return;
            }
            int passwd = Convert.ToInt16(textpasswd.Text, 10);
            if ((passwd == 0) || (passwd >= 10000)) {
                MessageBox.Show("请输入4位非全0密码");
                return;
            }
            sendhex[4] = (byte)(passwd / 256);
            sendhex[5] = (byte)(passwd % 256);
            send_modbus_data(sendhex);
            Thread.Sleep(100);
            byte[] sendhex_1 = { 0x01, 0x01, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex_1);
        }

        private void bt_setrootpasswd_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            byte[] sendhex = { 0x01, 0x05, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0 };
            if (textRootPasswd.Text == "")
            {
                MessageBox.Show("请输入管理员密码");
                return;
            }
            int passwd = Convert.ToInt16(textRootPasswd.Text, 10);
            if ((passwd == 0) || (passwd >= 10000))
            {
                MessageBox.Show("请输入4位非全0管理员密码");
                return;
            }
            sendhex[4] = (byte)(passwd / 256);
            sendhex[5] = (byte)(passwd % 256);
            send_modbus_data(sendhex);
            Thread.Sleep(100);
            byte[] sendhex_1 = { 0x01, 0x01, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex_1);
        }

        private void bt_synctime_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            byte[] sendhex = { 0x01, 0x05, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0 };
            DateTime now = DateTime.Now;
            sendhex[4] = (byte)(now.Year - 2000);
            sendhex[5] = (byte)(now.Month);
            send_modbus_data(sendhex);
            Thread.Sleep(20);
            sendhex[3] = 5;
            sendhex[4] = (byte)now.Day;
            sendhex[5] = (byte)now.Hour;
            send_modbus_data(sendhex);
            Thread.Sleep(20);
            sendhex[3] = 6;
            sendhex[4] = (byte)now.Minute;
            sendhex[5] = (byte)now.Second;
            send_modbus_data(sendhex);
            Thread.Sleep(20);
            sendhex[1] = 1;
            sendhex[3] = 4;
            sendhex[4] = 0;
            sendhex[5] = 1;
            send_modbus_data(sendhex);
            text_curtime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }

        private void Get_History_Log_TotalNum()
        {
            byte[] sendhex = { 0x01, 0x01, 0x0, 0x7, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex);
        }

        private void Get_History_Log_Data()
        {
            byte[] sendhex = { 0x01, 0x01, 0x0, 0x8, 0x0, 0x1, 0x0, 0x0 };

            send_modbus_data(sendhex);
        }

        private void 日志查询ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            pCan.Visible = false;
            pModbus.Visible = true;
            gpBox_SelfCheck.Visible = false;
            gpBox_passwd.Visible = false;
            gpBox_historylog.Visible = true;
            progressBar.Visible = false;
            cbBox_pagepernum.Text = "10";
            btn_sync_historylog.Enabled = true;
            btn_downlog.Enabled = true;
        }

        private void 基本功能ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            pCan.Visible = false;
            pModbus.Visible = true;
            gpBox_SelfCheck.Visible = true;
            gpBox_passwd.Visible = true;
            gpBox_historylog.Visible = false;
        }

        private void cbBox_pagepernum_SelectedIndexChanged(object sender, EventArgs e)
        {
            
        }

        private void btn_sync_historylog_Click(object sender, EventArgs e)
        {
            
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }
            Get_History_Log_TotalNum();
            Thread.Sleep(20);
            Get_History_Log_Data();
            progressBar.Visible = true;
            progressBar.Value = 0;
            btn_sync_historylog.Enabled = false;
            btn_downlog.Enabled = false;
        }

        private void bt_priv_Click(object sender, EventArgs e)
        {
            if (textBox_curpage.Text == "")
            {
                return;
            }

            int pagepernum = Convert.ToInt32(cbBox_pagepernum.Items[cbBox_pagepernum.SelectedIndex].ToString());
            int cur_page = Convert.ToInt32(textBox_curpage.Text);

            if (cur_page == 1)
            {
                return;
            }

            cur_page = cur_page - 1;
            textBox_curpage.Text = cur_page.ToString();
            g_history_log_index -= pagepernum;
            refresh_log_page();
        }

        private void bt_next_Click(object sender, EventArgs e)
        {
            if (textBox_curpage.Text == "")
            {
                return;
            }

            int pagepernum = Convert.ToInt32(cbBox_pagepernum.Items[cbBox_pagepernum.SelectedIndex].ToString());
            int cur_page = Convert.ToInt32(textBox_curpage.Text);
            int max_page = Convert.ToInt32(lb_totalNum.Text);

            if (cur_page == max_page)
            {
                return;
            }
            cur_page = cur_page + 1;
            textBox_curpage.Text = cur_page.ToString();
            g_history_log_index += pagepernum;
            refresh_log_page();

        }

        private void bt_jump_Click(object sender, EventArgs e)
        {
            if (textBox_curpage.Text == "")
            {
                return;
            }
            int pagepernum = Convert.ToInt32(cbBox_pagepernum.Items[cbBox_pagepernum.SelectedIndex].ToString());
            int cur_page = Convert.ToInt32(textBox_curpage.Text);
            int max_page = Convert.ToInt32(lb_totalNum.Text);

            if (cur_page > max_page)
            {
                return;
            }
            if (cur_page < 1)
            {
                return;
            }
            g_history_log_index = (cur_page - 1) * pagepernum;
            refresh_log_page();

        }

        private void btn_clear_history_Click(object sender, EventArgs e)
        {
            checkedListBox_history.Items.Clear();
        }

        private void msgBox_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void btn_show_hopepage_Click(object sender, EventArgs e)
        {
            show_homepage();
        }

        private void btn_refresh_log_Click(object sender, EventArgs e)
        {
            
            refresh_log_page();
        }

        private void listBox_history_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void btn_del_log_Click(object sender, EventArgs e)
        {
            int index = 0;

            for (int i = 0; i < checkedListBox_history.Items.Count; i++)
            {
                if (checkedListBox_history.GetItemChecked(i))
                {
                    g_history_data.RemoveAt(g_history_log_index + i - index);
                    g_history_log_totalnum--;
                    index++;
                }
            }

            lb_total_lognum.Text = g_history_log_totalnum.ToString("0000");
            int page_per_num = Convert.ToInt32(cbBox_pagepernum.Items[cbBox_pagepernum.SelectedIndex].ToString());
            if (g_history_log_totalnum % page_per_num == 0)
            {
                lb_totalNum.Text = (g_history_log_totalnum / page_per_num).ToString();
            }
            else
            {
                lb_totalNum.Text = ((g_history_log_totalnum / page_per_num) + 1).ToString();
            }
            refresh_log_page();
        }

        private void btn_downlog_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            progressBar.Visible = true;
            progressBar.Value = 0;
            btn_sync_historylog.Enabled = false;
            btn_downlog.Enabled = false;

            /* 清空flash */
            byte[] sendhex = { 0x01, 0x05, 0x0, 0xa, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex);
            progressBar.Value = 5;
        }

        private void btn_get_can_addr_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            /* 清空flash */
            byte[] sendhex = { 0x01, 0x01, 0x0, 0xc, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex);
        }

        private void btn_get_can_dev_type_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            /* 清空flash */
            byte[] sendhex = { 0x01, 0x01, 0x0, 0xd, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex);
        }

        private void btn_del_log_more_Click(object sender, EventArgs e)
        {
            int index = 0;

            if (textBox_dellog_start.Text == "")
            {
                MessageBox.Show("请输入删除日志的开始序号");
                return;
            }

            if (textBox_dellog_end.Text == "")
            {
                MessageBox.Show("请输入删除日志的结束序号");
                return;
            }

            int start_index = Convert.ToInt32(textBox_dellog_start.Text);
            int end_index = Convert.ToInt32(textBox_dellog_end.Text);

            if (start_index >= end_index)
            {
                MessageBox.Show("开始序号必须小于结束序号");
                return;
            }

            if (start_index < 1)
            {
                MessageBox.Show("开始序号从1开始");
                return;
            }

            if (end_index > g_history_log_totalnum)
            {
                MessageBox.Show("结束序号大于当前最大值");
                return;
            }

            for (int i = start_index - 1; i < end_index; i++)
            {
                g_history_data.RemoveAt(i - index);
                g_history_log_totalnum--;
                index++;
            }

            lb_total_lognum.Text = g_history_log_totalnum.ToString("0000");
            int page_per_num = Convert.ToInt32(cbBox_pagepernum.Items[cbBox_pagepernum.SelectedIndex].ToString());
            if (g_history_log_totalnum % page_per_num == 0)
            {
                lb_totalNum.Text = (g_history_log_totalnum / page_per_num).ToString();
            }
            else
            {
                lb_totalNum.Text = ((g_history_log_totalnum / page_per_num) + 1).ToString();
            }
            refresh_log_page();
        }

        private void btn_selftest_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            label_selftest_0.Text = "提示：";
            label_selftest_1.Text = "提示：";
            label_selftest_2.Text = "提示：";
            label_selftest_3.Text = "提示：";
            label_selftest_4.Text = "提示：";
            label_selftest_5.Text = "提示：";
            label_selftest_6.Text = "提示：";
            checkBox_self_test_0.Text = "待测试";
            checkBox_self_test_1.Text = "待测试";
            checkBox_self_test_2.Text = "待测试";
            checkBox_self_test_3.Text = "待测试";
            checkBox_self_test_4.Text = "待测试";
            checkBox_self_test_5.Text = "待测试";
            checkBox_self_test_6.Text = "待测试";
            checkBox_self_test_0.Checked = false;
            checkBox_self_test_1.Checked = false;
            checkBox_self_test_2.Checked = false;
            checkBox_self_test_3.Checked = false;
            checkBox_self_test_4.Checked = false;
            checkBox_self_test_5.Checked = false;
            checkBox_self_test_6.Checked = false;
            byte[] sendhex = { 0x01, 0x01, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex);
        }

        private void btn_stop_selftest_Click(object sender, EventArgs e)
        {
            if (g_modbus_mode == 0)
            {
                MessageBox.Show("请进入指令模式");
                return;
            }

            label_selftest_0.Text = "提示：";
            label_selftest_1.Text = "提示：";
            label_selftest_2.Text = "提示：";
            label_selftest_3.Text = "提示：";
            label_selftest_4.Text = "提示：";
            label_selftest_5.Text = "提示：";
            label_selftest_6.Text = "提示：";
            checkBox_self_test_0.Text = "待测试";
            checkBox_self_test_1.Text = "待测试";
            checkBox_self_test_2.Text = "待测试";
            checkBox_self_test_3.Text = "待测试";
            checkBox_self_test_4.Text = "待测试";
            checkBox_self_test_5.Text = "待测试";
            checkBox_self_test_6.Text = "待测试";
            checkBox_self_test_0.Checked = false;
            checkBox_self_test_1.Checked = false;
            checkBox_self_test_2.Checked = false;
            checkBox_self_test_3.Checked = false;
            checkBox_self_test_4.Checked = false;
            checkBox_self_test_5.Checked = false;
            checkBox_self_test_6.Checked = false;
            byte[] sendhex = { 0x01, 0x01, 0x0, 0x11, 0x0, 0x1, 0x0, 0x0 };
            send_modbus_data(sendhex);
        }
    }
}

namespace CRC16
{
    class CRC_16
    {
        public byte[] getcrc(byte[] bytes, int offset, int length)
        {
            if (length > 0)
            {
                ushort crc = 0xFFFF;
                for (int i = offset; i < length; i++)
                {
                    crc = (ushort)(crc ^ bytes[i]);
                    for (int j = 0; j < 8; j++)
                    {
                        if ((crc & 1) != 0)
                        {
                            crc = (ushort)((crc >> 1) ^ 0xA001);
                        }
                        else
                        {
                            crc = (ushort)(crc >> 1);
                        }
                    }
                }
                byte high_order = (byte)((crc & 0xFF00) >> 8);
                byte Low_order = (byte)(crc & 0x00FF);
                return new byte[] { high_order, Low_order };
            }
            return new byte[] { 0x00, 0x00 };
        }
    }
}
